﻿using System;

namespace SoftwareConsulting.BI11.NumericalMethods.Statistics
{
    /// <summary>
    /// Генератор случайных чисел Митчелла-Мура
    /// </summary>
    public class RandomMitchellMooreGenerator
    {	    
        private double[] _beforeRandoms;	    
        private int _lastIndex;	    
        private int _lowIndex;

        /// <summary>
        /// Конструктор класса по умолчанию
        /// </summary>
        public RandomMitchellMooreGenerator() : 
            this(55, 24)
        {
        }

        /// <summary>
        /// Конструктор класса
        /// </summary>
        /// <param name="seeds"></param>
        /// <param name="index"></param>
        public RandomMitchellMooreGenerator(double[] seeds, int index)
        {
            _lastIndex = seeds.Length;
            _beforeRandoms = new double[_lastIndex];
            Array.Copy(seeds, _beforeRandoms, --_lastIndex);
            _lowIndex = index - 1;
        }

        /// <summary>
        /// Конструктор класса
        /// </summary>
        /// <param name="indexHigh">высокий индекс</param>
        /// <param name="indexLow">низкий индекс</param>
        public RandomMitchellMooreGenerator(int indexHigh, int indexLow)
        {
            Random generator = new Random();
            _beforeRandoms = new double[indexHigh];
            for (int i = 0; i < indexHigh; i++)
                _beforeRandoms[i] = generator.NextDouble();
            _lastIndex = indexHigh - 1;
            _lowIndex = indexLow - 1;
        }

        /// <summary>
        /// Возвращает следующее случайное вещественное число
        /// </summary>
        /// <returns></returns>
        public double NextDouble()
        {
            double x = _beforeRandoms[_lastIndex--] + _beforeRandoms[_lowIndex--];
            if (_lastIndex < 0)
                _lastIndex = _beforeRandoms.Length - 1;
            if (_lowIndex < 0)
                _lowIndex = _beforeRandoms.Length - 1;
            return (_beforeRandoms[_lastIndex] = x < 1.0 ? x : x - 1);
        }

        /// <summary>
        /// Возвращает следующее случайное целое число
        /// </summary>
        /// <param name="max">максимальное положительное число, которое может быть сгенерировано (минус 1)</param>
        /// <returns></returns>
        public long NextInteger(long max)
        {
            return (long)(max * NextDouble());
        }
    }
}
